home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Graphics / SPD / Sources / drv_mac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  30.4 KB  |  1,160 lines  |  [TEXT/R*ch]

  1. /*==============================================================================
  2. Project:    SPD
  3.  
  4. File:    drv_mac.c
  5.  
  6. Description:
  7. Mac-specific code for initialization & displaying.
  8. ------------------------------------------------------------------------------
  9. Author:
  10.     Alexander Enzmann, [70323,2461]
  11.     Eduard Schwan, [71513,2161]
  12. ------------------------------------------------------------------------------
  13. Change History:
  14.     9212??    [ae]    Created.
  15.     921214    [esp]    Updated to compile under MPW C as well as Think C.
  16.     930117    [esp]    Added MacInit, MacMultiTask, MacShutDown, GetOptions code
  17.     930317    [esp]    Added MoveToMaxDevice, environs check, collapsed multiple
  18.                     dialogs to 1, changed display_init to accept bg_color
  19.     930418    [esp]    Added driver checks.
  20.     930803    [esp]    Changed argv parameters to match new 3.1a format.
  21.     930805    [esp]    Added radios for the -t/-c output_format switches.
  22.     930817    [esp]    Added ColorQD check in Display_Init.
  23.     930918    [esp]    Fixed up logic for input parm prompting.
  24.     930918    [esp]    Added grody quick fix to redraw please-wait dlg on switchin.
  25.     940725    [esp]    Removed special palette, use System palette to avoid Finder color snatching
  26. ==============================================================================*/
  27.  
  28. #include <stdio.h>        /* sprintf, etc */
  29. #include <stdlib.h>        /* atoi, etc */
  30.  
  31. /*==== Macintosh-specific headers ====*/
  32. #include <Controls.h>
  33. #include <Desk.h>
  34. #include <Dialogs.h>
  35. #include <Files.h>
  36. #include <Memory.h>            /* BlockMove */
  37. #include <Menus.h>
  38. #include <OSEvents.h>
  39. #include <OSUtils.h>
  40. #include <Packages.h>
  41. #include <QuickDraw.h>
  42. #include <Palettes.h>
  43. #include <Resources.h>
  44. #include <Types.h>
  45. #include <Windows.h>
  46. #include <sound.h>
  47. #include <AppleEvents.h>
  48. #include <GestaltEqu.h>
  49. #include <Folders.h>
  50. #include <errors.h>            /* dupFNErr, etc */
  51. #include <Fonts.h>            /* checkMark */
  52. #include <segload.h>        /* UnloadSeg */
  53. #include <traps.h>            /* _Unimplemented */
  54. #include <StandardFile.h>    /* SFPutFile */
  55. #include <string.h>            /* strcpy/cat */
  56. #include <toolutils.h>        /* BitTst, GetCursor, etc */
  57.  
  58. #ifdef applec
  59. #include <strings.h>        /* p2cstr */
  60. #endif
  61.  
  62. #include "def.h"
  63. #include "drv.h"
  64. #include "lib.h"        /* for output types */
  65.  
  66. /*------------------------------------------------------------*/
  67. /* These #defines map MPW C names into their Think C equivalent */
  68. #ifdef THINK_C
  69. // <esp>
  70. // #define    c2pstr    CtoPstr
  71. // #define    p2cstr    PtoCstr
  72. #endif THINK_C
  73.  
  74. #define    kOSEvent                app4Evt    /* event used by MultiFinder */
  75. #define    kSuspendResumeMessage    1        /* high byte of suspend/resume event message */
  76.  
  77. #define kMouseCursorID 1000    // mouse cursor resource ID
  78.  
  79. /* #define    USE_CUSTOM_PALETTE        1        /* turn on to attach special palette */
  80.  
  81. /*------------------------------------------------------------*/
  82. // constants for positioning the default popup item within its box
  83. #define    SLOP_LEFT    13        // leave this much space on left of title
  84. #define    SLOP_RIGHT    12        // this much on right
  85. #define    SLOP_BOTTOM     5        // this much below baseline
  86.  
  87. // general dialog constants
  88. #define    DlogID_BADENV        1000
  89. #define    DlogID_WAIT            1001
  90. #define    DlogID_NOCOLORQD    1002
  91. #define    DlogID_GETOPTS        2000
  92.  
  93. // # of lines or pixels to draw between multitask calls
  94. #define    MAX_TASK_WAIT    50
  95.  
  96. typedef struct
  97. {
  98.     MenuHandle    fMenuHandle;    // our popUp menu
  99.     short        fMenuID;        // our popUp menu ID
  100.     DialogPtr    fParentDialog;    // our dialog pointer
  101.     short        fPopupItemID;    // our popUp dialog user item ID
  102.     Rect        fPopupBounds;    // boundsrect of popup menu
  103.     short        fTitleItemID;    // our popUp title user item ID
  104.     Rect        fTitleBounds;    // boundsrect of our popUp's title box
  105.     short        fLastChoice;    // the last-chosen item from the pop-up menu
  106. } popupMenuRec_t, *popupMenuPtr_t, **popupMenuHdl_t;
  107.  
  108. /*------------------------------------------------------------*/
  109. short        gMacRayTracerKind = OUTPUT_RT_DEFAULT;
  110. short        gMacParmSize = 2;
  111. Boolean        gMacDoBuiltIn = true;    /* TRUE= OUTPUT_CURVES, FALSE = OUTPUT_PATCHES */
  112. char        gInFileName[64];
  113.  
  114. /*------------------------------------------------------------*/
  115. static WindowPtr    myWindow;
  116. #if defined(USE_CUSTOM_PALETTE)
  117. static PaletteHandle PolyPalette;
  118. #endif
  119. static int            maxx = 460;
  120. static int            maxy = 300;
  121. static int            gMultiTaskCount = 0;
  122.  
  123. static Boolean        gHasSizePrompt;
  124. static Boolean        gHasInFilePrompt;
  125. static Boolean        gHasPatchPrompt;
  126.  
  127. static COORD3        bkgnd_color;
  128. static int            display_active_flag = 0;
  129. static double        X_Display_Scale = 1.0;
  130. static double        Y_Display_Scale = 1.0;
  131. static SysEnvRec    gSysEnvirons;
  132. static DialogPtr    gDialogPtr = NULL;
  133.  
  134. static char            *macArgv[] =    {NULL, NULL, NULL, NULL, NULL,
  135.                                     NULL, NULL, NULL, NULL, NULL};
  136. static char            macArgvBuffer[200];        // fake argc/argv
  137. static char            *argvCurrent;
  138. static popupMenuRec_t    gPopupRec;
  139.  
  140. /*------------------------------------------------------------*/
  141. void MacMultiTask();
  142.  
  143.  
  144. static void DrawDownTriangle(register short h, register short v)
  145. {
  146.     register short i;
  147.  
  148.     for (i = 0; i < 6; ++i)    {
  149.         MoveTo(h + 5 - i, v - i);
  150.         Line(2*i, 0);
  151.     }
  152. }
  153.  
  154.  
  155. /*------------------------------------------------------------*/
  156. // Draw the popup menu (called by Dialog Mgr for updates, and by our filterproc)
  157. static pascal void DrawPopupMenu(DialogPtr pDialogPtr, short pItem)
  158. {
  159. #pragma unused (pItem, pDialogPtr)
  160.     short        newWid, newLen, wid;
  161.     PenState    savePen;
  162.     Rect        aRect;
  163.     Str255        theItemText;
  164.     FontInfo    fontInfo;
  165.  
  166.     SetPort(pDialogPtr);
  167.  
  168.     GetPenState(&savePen);
  169.     GetFontInfo(&fontInfo);
  170.  
  171.     // get currently-selected item text
  172.     GetItem(gPopupRec.fMenuHandle, gPopupRec.fLastChoice, theItemText);
  173.  
  174.     // get the menu bounds
  175.     aRect = gPopupRec.fPopupBounds;
  176.     InsetRect(&aRect, -1, -1); // make it a little bigger
  177.  
  178.     // Insure that the item fits. Truncate it and add an ellipses (".") if it doesn't
  179.     wid = (aRect.right-aRect.left) - (CharWidth(checkMark)+SLOP_RIGHT+4); // available string area
  180.     newWid = StringWidth(theItemText); // get current width
  181.     if (newWid > wid)
  182.     {    // doesn't fit - truncate it
  183.         newLen = theItemText[0]; // current length in characters
  184.         wid = wid - CharWidth('…'); // subtract width of ellipses
  185.  
  186.         do    { // until it fits (or we run out of characters)
  187.             // drop the last character and its width
  188.             newWid -= CharWidth(theItemText[newLen]);
  189.             newLen--;
  190.         } while ((newWid > wid) && (newLen > 0));
  191.  
  192.         // add the ellipses character
  193.         newLen++; // add room for elipsis character
  194.         theItemText[newLen] = '…';
  195.         theItemText[0] = newLen; // set the new true length
  196.     }
  197.  
  198.     // draw the box
  199.     PenSize(1, 1);
  200.     FrameRect(&aRect);
  201.     // and its drop shadow
  202.     MoveTo(aRect.right, aRect.top+2);
  203.     LineTo(aRect.right, aRect.bottom);
  204.     LineTo(aRect.left+2, aRect.bottom);
  205.  
  206.     // draw the string
  207.     MoveTo(aRect.left+CharWidth(checkMark)+2, aRect.top+fontInfo.ascent);
  208.     DrawString(theItemText);
  209.  
  210.     DrawDownTriangle(aRect.right-SLOP_RIGHT-1, aRect.top+fontInfo.ascent);
  211.  
  212.     SetPenState(&savePen);
  213. } // DrawPopupMenu
  214.  
  215.  
  216. /*------------------------------------------------------------*/
  217. // Initialize the popup menu/dialog record, returns true if successful
  218. Boolean IPopupMenu(DialogPtr pDialogPtr, short pMenuID, short pTitleItemID, short pPopupItemID,
  219.                 short pCurrentChoice)
  220. {
  221.     Handle        theItem;
  222.     short        theItemType;
  223.     Boolean        returnValue;
  224.  
  225.     returnValue = false;
  226.     gPopupRec.fMenuHandle    = GetMenu(pMenuID);        // our popUp menu
  227.     if ((gPopupRec.fMenuHandle != NULL) && (pDialogPtr != NULL))
  228.     {
  229.         gPopupRec.fMenuID        = pMenuID;            // our popUp menu ID
  230.         gPopupRec.fParentDialog    = pDialogPtr;        // our dialog pointer
  231.         gPopupRec.fPopupItemID    = pPopupItemID;        // our popUp dialog user item ID
  232.         gPopupRec.fTitleItemID    = pTitleItemID;        // our popUp title user item ID
  233.  
  234.         gPopupRec.fLastChoice    = pCurrentChoice;    // the last-chosen item from the pop-up menu
  235.         SetItemMark(gPopupRec.fMenuHandle, pCurrentChoice, checkMark); // check this item
  236.  
  237.         GetDItem(pDialogPtr, pTitleItemID, &theItemType, &theItem, &gPopupRec.fTitleBounds); // boundsrect of our popUp's title box
  238.         GetDItem(pDialogPtr, pPopupItemID, &theItemType, &theItem, &gPopupRec.fPopupBounds); // boundsrect of its prompt
  239.         CalcMenuSize(gPopupRec.fMenuHandle);
  240.         // install our Draw proc (DrawPopupMenu)
  241.         SetDItem(pDialogPtr, pPopupItemID, theItemType, (Handle)DrawPopupMenu, &gPopupRec.fPopupBounds); // boundsrect of its prompt
  242.         returnValue = true;
  243.     }
  244.     return returnValue;
  245. } // IPopupMenu
  246.  
  247.  
  248. /*------------------------------------------------------------*/
  249. // Filterproc for popup userItem hits on mouse down (call from your dialog filter proc)
  250. pascal Boolean PopupMouseDnDialogFilterProc(DialogPtr pDialogPtr, EventRecord *pEventPtr, short *pItemHitPtr)
  251. {
  252. Point    mouseLoc, popLoc;
  253. short    newChoice, theItem;
  254. long    chosen;
  255. Boolean    myFilter;
  256.  
  257.     // pre-initialize return values
  258.     *pItemHitPtr = 0;
  259.     myFilter = false;
  260.  
  261.     if (pEventPtr->what == mouseDown)
  262.     {
  263.         SetPort(pDialogPtr);
  264.  
  265.         mouseLoc = pEventPtr->where; // copy the mouse position
  266.         GlobalToLocal(&mouseLoc); // convert it to local dialog coordinates
  267.  
  268.         // Was the click in a popup item?  NOTE: FindDItem is zero-based!
  269.         theItem = FindDItem(pDialogPtr, mouseLoc);
  270.         if ((theItem + 1) == gPopupRec.fPopupItemID)
  271.         {
  272.             // We're going to pop up our menu. Insert our menu into the menu list,
  273.             // then call CalcMenuSize (to work around a bug in the Menu Manager),
  274.             // then call PopUpMenuSelect and let the user drag around. Note that the
  275.             // (top,left) parameters to PopUpMenuSelect are our item's, converted to
  276.             // global coordinates.
  277.             InvertRect(&gPopupRec.fTitleBounds); // hilight the title
  278.             InsertMenu(gPopupRec.fMenuHandle, -1); // insert our menu in the menu list
  279.             popLoc = *(Point*)(&gPopupRec.fPopupBounds.top); // copy our item's topleft
  280.             LocalToGlobal(&popLoc); // convert back to global coords
  281.             CalcMenuSize(gPopupRec.fMenuHandle); // Work around Menu Mgr bug
  282.             chosen = PopUpMenuSelect(gPopupRec.fMenuHandle,
  283.                             popLoc.v, popLoc.h, gPopupRec.fLastChoice);
  284.             DeleteMenu(gPopupRec.fMenuID); // Remove our menu from the menu list
  285.             InvertRect(&gPopupRec.fTitleBounds); // unhilight the title
  286.  
  287.             // Was something chosen?
  288.             if (chosen)
  289.             {
  290.                 // get the chosen item number
  291.                 newChoice = chosen & 0x0000ffff;
  292.                 if (newChoice != gPopupRec.fLastChoice)
  293.                 {
  294.                     // the user chose an item other than the current one
  295.                     SetItemMark(gPopupRec.fMenuHandle, gPopupRec.fLastChoice, noMark); // unmark the old choice
  296.                     SetItemMark(gPopupRec.fMenuHandle, newChoice, checkMark); // mark the new choice
  297.                     gPopupRec.fLastChoice = newChoice; // update the current choice
  298.  
  299.                     // Draw the new title
  300.                     EraseRect(&gPopupRec.fPopupBounds);
  301.                     DrawPopupMenu(pDialogPtr, gPopupRec.fPopupItemID);
  302.  
  303.                     myFilter = true; // dialog is over
  304.                     // have ModalDialog return that the user changed items
  305.                     *pItemHitPtr = gPopupRec.fPopupItemID;
  306.                 } // if new choice
  307.             } // if chosen
  308.         } // if our popup Item
  309.     } // if mousedown
  310.  
  311.     return myFilter;
  312.  
  313. } // PopupMouseDnDialogFilterProc
  314.  
  315.  
  316. /*------------------------------------------------------------*/
  317. /* Returns the short version string in the application's version resource */
  318. static void GetAppVersionPString(short versID, Str31 versionString)
  319. {
  320.     VersRecHndl    versHandle;        // VersRecHndl declared in MPW's <files.h>
  321.     
  322.     /* Get the resource string from app, 'vers' versID (1 or 2) resource! */
  323.     versionString[0] = '\0';
  324.     versHandle = (VersRecHndl)GetResource('vers',versID);
  325.     if (versHandle)
  326.     {
  327.         HLock((Handle)versHandle);
  328.         BlockMove((**versHandle).shortVersion, versionString,
  329.                     (**versHandle).shortVersion[0]+1);
  330.         ReleaseResource((Handle)versHandle);
  331.     }
  332. } // GetAppVersionPString
  333.  
  334.  
  335. /*------------------------------------------------------------*/
  336. static void MoveWindowToMaxDevice(WindowPtr theWindow)
  337. {
  338.     Point        upperCorner;
  339.     Rect        mainRect;
  340.     Rect        deviceRect;
  341.     Rect        windRect;
  342.     Rect        maxDragBounds;
  343.     GDHandle    theMainGDevice, theMaxGDevice;
  344.  
  345.     if (theWindow == NULL)
  346.         return;
  347.  
  348.     // Set up bounds for all devices
  349.     SetRect(&maxDragBounds, -32000, -32000, 32000, 32000);
  350.  
  351.     // Find main screen bounds
  352.     theMainGDevice = GetMainDevice();
  353.     mainRect = (**theMainGDevice).gdRect;
  354.  
  355.     // Find deepest screen bounds
  356.     theMaxGDevice = GetMaxDevice(&maxDragBounds);
  357.     deviceRect = (**theMaxGDevice).gdRect;
  358.  
  359.     // if Max is the same as Main, we need do nothing! Already in place!
  360.     if (EqualRect(&mainRect, &deviceRect))
  361.         return;
  362.  
  363.     // where's the window, relative to main screen
  364.     windRect = theWindow->portRect;
  365.     // yah, but where is it really?
  366.     SetPort(theWindow);
  367.     LocalToGlobal((Point*)&windRect.top);
  368.     LocalToGlobal((Point*)&windRect.bottom);
  369.  
  370.     // find relative spot on new device
  371.     upperCorner.h = windRect.left;
  372.     upperCorner.v = windRect.top;
  373.     // now relative to new screen
  374.     upperCorner.h = upperCorner.h + deviceRect.left;
  375.     upperCorner.v = upperCorner.v + deviceRect.top;
  376.  
  377.     // now move it there
  378.     MoveWindow(theWindow, upperCorner.h, upperCorner.v, true);
  379.  
  380. } // MoveWindowToMaxDevice
  381.  
  382.  
  383.  
  384. /*------------------------------------------------------------*/
  385. // This is a user item proc for drawing default dialog button outlines */
  386. static pascal void outlineDefaultButton(DialogPtr theDialog, short theItem)
  387. {
  388. #pragma unused (theItem)
  389.     PenState    SavePen;
  390.     short        itemType;
  391.     Handle        itemHandle;
  392.     Rect        dispRect;
  393.  
  394.     GetPenState(&SavePen);
  395.     /* use 'ok' (#1) item's rectangle */
  396.     GetDItem(theDialog, ok, &itemType, &itemHandle, &dispRect);
  397.     SetPort(theDialog);
  398.     PenSize(3, 3);
  399.     InsetRect(&dispRect, -4, -4);
  400.     FrameRoundRect(&dispRect, 16, 16);
  401.     SetPenState(&SavePen);
  402. } // outlineDefaultButton
  403.  
  404.  
  405. /*------------------------------------------------------------*/
  406. /* Sets dialog #3 item's display proc to draw outline around item #1 */
  407. static void SetupDefaultButton(DialogPtr theDialog)
  408. {
  409.     short    itemtype;
  410.     Rect    itemrect;
  411.     Handle    tempHandle;
  412.  
  413.     /* Set up User item (always #3) to display a border around OK button (#1) */
  414.     GetDItem(theDialog, 3, &itemtype, &tempHandle, &itemrect);
  415.     SetDItem(theDialog, 3, itemtype, (Handle)&outlineDefaultButton, &itemrect);
  416. } // SetupDefaultButton
  417.  
  418.  
  419. /*------------------------------------------------------------*/
  420. // Move a dialog item (whatever type it is) to absolute position h,v
  421. static void MoveDItem(DialogPtr theDialog, short theItemID, short h, short v)
  422. {
  423.     short    itemtype;
  424.     Rect    itemrect;
  425.     Handle    tempHandle;
  426.  
  427.     // NOTE: We should check for CtrlItem here and call MoveControl instead, just lazy!
  428.     // get item
  429.     GetDItem(theDialog, theItemID, &itemtype, &tempHandle, &itemrect);
  430.     // move its view rect (to absolute pos)
  431.     OffsetRect(&itemrect, h-itemrect.left, v-itemrect.top);
  432.     // set new rect value back into item
  433.     SetDItem(theDialog, theItemID, itemtype, tempHandle, &itemrect);
  434. } // MoveDItem
  435.  
  436.  
  437. /*------------------------------------------------------------*/
  438. static DialogPtr SetupNewDialog(short theDialogID, Boolean doOutlineDefault)
  439. {
  440.     DialogPtr    aDialog;
  441.  
  442.     aDialog = GetNewDialog(theDialogID, NULL, (WindowPtr)-1);
  443.  
  444.     /* "default" the OK button */
  445.     if ((aDialog != NULL) && doOutlineDefault)
  446.         SetupDefaultButton(aDialog);
  447.  
  448.     return aDialog;
  449.  
  450. } // SetupNewDialog
  451.  
  452.  
  453. /*------------------------------------------------------------*/
  454. static void FatalErrDialog(short DlogID)
  455. {
  456.     short        itemHit;
  457.  
  458.     SysBeep(4);
  459.     gDialogPtr = SetupNewDialog(DlogID, true);
  460.     if (gDialogPtr)
  461.     {
  462.         ShowWindow(gDialogPtr);
  463.         ModalDialog(NULL, &itemHit);
  464.     }
  465.     else
  466.     {
  467.         /* two beeps means something is very wrong! */
  468.         SysBeep(4);
  469.     }
  470.     ExitToShell();
  471. } // FatalErrDialog
  472.  
  473.  
  474. /*------------------------------------------------------------*/
  475. static Boolean GetInputFile(char * theInFileName)
  476. {
  477.     SFReply        reply;
  478.     Point        where;
  479.     SFTypeList    theTypes;
  480.  
  481.     where.h = 30;
  482.     where.v = 50;
  483.  
  484.     /* prompt */
  485.     theTypes[0] = 'TEXT';
  486.     SFGetFile(where, "\p", (FileFilterProcPtr)NULL, 1, theTypes, (DlgHookProcPtr)NULL, &reply);
  487.     if (reply.good)
  488.     {
  489.         /* return it */
  490.         BlockMove(reply.fName, theInFileName, 1+reply.fName[0]);
  491.         p2cstr((StringPtr)theInFileName);
  492.         SetVol(NULL, reply.vRefNum); /* set current folder */
  493.         return true;
  494.     }
  495.     else
  496.         return false;
  497. } // GetInputFile
  498.  
  499.  
  500. /*------------------------------------------------------------*/
  501. #ifdef FUTURE_USE
  502. static Boolean GetOutputFile(char * theOutFileName)
  503. {
  504.     SFReply        reply;
  505.     Point        where;
  506.     char        pOutFileName[64];
  507.  
  508.     GetBestDlgPoint(&where);
  509.     /* pre-fill output filename with old one */
  510.     strcpy(pOutFileName, theOutFileName);
  511.     c2pstr(pOutFileName);
  512.     /* prompt */
  513.     SFPutFile(where, "\pCreate output Coil file.", pOutFileName,
  514.                 (DlgHookProcPtr)NULL, &reply);
  515.     if (reply.good)
  516.     {
  517.         /* return it */
  518.         BlockMove(reply.fName, theOutFileName, 1+reply.fName[0]);
  519.         p2cstr(theOutFileName);
  520.         SetVol(NULL, reply.vRefNum); /* set current folder */
  521.         return true;
  522.     }
  523.     else
  524.         return false;
  525. } // GetOutputFile
  526.  
  527. #endif FUTURE_USE
  528.  
  529.  
  530. /*------------------------------------------------------------*/
  531. static void
  532. ToolBoxInit()
  533. {
  534.     int            k;
  535.     EventRecord    anEvent;
  536.  
  537.     InitGraf(&qd.thePort);
  538.     InitFonts();
  539.     InitWindows();
  540.     InitMenus();
  541.     TEInit();
  542.     InitDialogs(0L);
  543.     InitCursor();
  544.  
  545.     /* create master pointer blocks for heap o' mallocs */
  546.     for (k=0; k<10; k++)
  547.         MoreMasters();
  548.  
  549.     // DTS Hocus Pocus to bring our app to the front
  550.     for (k = 1; k <= 3; k++)
  551.         EventAvail(everyEvent, &anEvent);
  552.  
  553.     // what kind of environment are we in, anyway?
  554.     SysEnvirons(1, &gSysEnvirons);
  555.     if    (
  556.         (gSysEnvirons.machineType < envMachUnknown)
  557.     ||    (gSysEnvirons.systemVersion < 0x0604)
  558.     ||    (gSysEnvirons.processor < env68020)
  559.         )
  560.     {
  561.         FatalErrDialog(DlogID_BADENV);
  562.     }
  563.  
  564. }
  565.  
  566.  
  567. /*------------------------------------------------------------*/
  568. #if defined(USE_CUSTOM_PALETTE)
  569. static int
  570. determine_color_index(color)
  571.    COORD3 color;
  572. {
  573.    int i;
  574.    unsigned char r, g, b;
  575.  
  576.    i = 255.0 * color[Z];
  577.    if (i<0) i=0;
  578.    else if (i>=256) i = 255;
  579.    b = (unsigned char)i;
  580.  
  581.    i = 255.0 * color[Y];
  582.    if (i<0) i=0;
  583.    else if (i>=256) i = 255;
  584.    g = (unsigned char)i;
  585.  
  586.    i = 255.0 * color[X];
  587.    if (i<0) i=0;
  588.    else if (i>=256) i = 255;
  589.    r = (unsigned char)i;
  590.  
  591.    return (r & 0xE0) | ((g & 0xE0) >> 3) | (b >> 6);
  592. } // determine_color_index
  593. #endif
  594.  
  595.  
  596. /*------------------------------------------------------------*/
  597. Coord3ToRGBColor(COORD3 c3color, RGBColor    * rgbc)
  598. {
  599.    rgbc->red    = c3color[R_COLOR]*65535.0;
  600.    rgbc->green  = c3color[G_COLOR]*65535.0;
  601.    rgbc->blue   = c3color[B_COLOR]*65535.0;
  602. } // Coord3ToRGBColor
  603.  
  604.  
  605. /*------------------------------------------------------------*/
  606. void
  607. display_clear()
  608. {
  609.    Rect re;
  610.  
  611. #if defined(USE_CUSTOM_PALETTE)
  612.    PmForeColor(determine_color_index(bkgnd_color));
  613. #else
  614.    RGBColor    rgbc;
  615.  
  616.    Coord3ToRGBColor(bkgnd_color, &rgbc);
  617.    RGBForeColor(&rgbc);
  618. #endif
  619.    re.top = 0;
  620.    re.left = 0;
  621.    re.right = maxx;
  622.    re.bottom = maxy;
  623.    PaintRect(&re);
  624. }
  625.  
  626.  
  627. /*------------------------------------------------------------*/
  628. void
  629. display_init(xres, yres, bk_color)
  630.    int xres, yres;
  631.    COORD3 bk_color;
  632. {
  633.    RGBColor c;
  634.    int i;
  635.    int r, g, b;
  636.    Rect re;
  637.    COORD3 cColor;
  638.  
  639.     // die if on a machine that has no Color QD
  640.    if (!gSysEnvirons.hasColorQD)
  641.    {
  642.         FatalErrDialog(DlogID_NOCOLORQD);
  643.    }
  644.  
  645.    // remember the background color
  646.    COPY_COORD3(bkgnd_color, bk_color);
  647.  
  648.    // if already displaying, just clear the screen and return
  649.    if (display_active_flag) {
  650.       display_clear();
  651.       return;
  652.       }
  653.  
  654.    display_active_flag = 1;
  655.  
  656.    re.top = 24;
  657.    re.left = 4;
  658.    re.right = re.left + maxx;
  659.    re.bottom = re.top + maxy;
  660.    myWindow = NewCWindow(0L, &re, "\pObject Display",
  661.             FALSE, plainDBox,
  662.             (WindowPtr)-1L, FALSE, 0L);
  663.  
  664. #if defined(USE_CUSTOM_PALETTE)
  665.    PolyPalette = NewPalette(256, 0L, pmTolerant, 0x0000);
  666.    c.red = c.green = c.blue = 0;
  667.    SetEntryColor(PolyPalette, 0, &c);
  668.  
  669.    i = 0;
  670.    for (r=0;r<8;r++)
  671.       for (g=0;g<8;g++)
  672.      for (b=0;b<4;b++) {
  673.         c.red   = r << 13;
  674.         c.green = g << 13;
  675.         c.blue  = b << 14;
  676.         SetEntryColor(PolyPalette, i, &c);
  677.         i++;
  678.         }
  679.  
  680.    /* Make sure the last entry is true white */
  681.    c.red   = 0xFFFF;
  682.    c.green = 0xFFFF;
  683.    c.blue  = 0xFFFF;
  684.    SetEntryColor(PolyPalette, i-1, &c);
  685.    SetEntryColor(PolyPalette, 0xFF, &c);
  686.  
  687.    SetPalette(myWindow, PolyPalette, TRUE);
  688. #endif
  689.  
  690.    /* Now open the window. */
  691.    MoveWindowToMaxDevice(myWindow);
  692.    ShowWindow(myWindow);
  693.    SetPort(myWindow);
  694.  
  695.    display_clear();
  696.  
  697.    if (xres > maxx)
  698.       X_Display_Scale = (double)maxx / (double)xres;
  699.    else
  700.       X_Display_Scale = 1.0;
  701.    if (yres > maxy)
  702.       Y_Display_Scale = (double)maxy / (double)yres;
  703.    else
  704.       Y_Display_Scale = 1.0;
  705.  
  706.    if (X_Display_Scale < Y_Display_Scale)
  707.       Y_Display_Scale = X_Display_Scale;
  708.    else if (Y_Display_Scale < X_Display_Scale)
  709.       X_Display_Scale = Y_Display_Scale;
  710.  
  711.    /* Outline the actual "visible" display area in the window */
  712.    SET_COORD3(cColor, 0.5, 0.5, 0.5); // grey
  713.    if (X_Display_Scale == 1.0) {
  714.       display_line(-xres/2, -yres/2, -xres/2, yres/2, cColor);
  715.       display_line( xres/2, -yres/2,  xres/2, yres/2, cColor);
  716.       }
  717.    if (Y_Display_Scale == 1.0) {
  718.       display_line(-xres/2,  yres/2,  xres/2,  yres/2, cColor);
  719.       display_line(-xres/2, -yres/2,  xres/2, -yres/2, cColor);
  720.       }
  721.  
  722.    return;
  723. }
  724.  
  725. /*------------------------------------------------------------*/
  726. void
  727. display_close(wait_flag)
  728.    int wait_flag;
  729. {
  730.     EventRecord    anEvent;
  731.     CursHandle    mouseCursorH;
  732.     
  733.     InitCursor(); // set it back to arrow
  734.     if (gDialogPtr)
  735.         DisposeDialog(gDialogPtr);
  736.  
  737.     mouseCursorH = GetCursor(kMouseCursorID);
  738.     if (mouseCursorH)
  739.         SetCursor(*mouseCursorH);
  740.  
  741.     /* hang around until the user is finished (this is grody, but works) */
  742.     if (wait_flag)
  743.     {
  744.         SysBeep(4);
  745.         while (!Button())
  746.             EventAvail(everyEvent, &anEvent);
  747.     }
  748.  
  749.     /* when all done, close the window on exit */
  750.     if (myWindow)
  751.         CloseWindow(myWindow);
  752.  
  753.     InitCursor(); // set it back to arrow
  754. }
  755.  
  756. /*------------------------------------------------------------*/
  757. static void
  758. putpixel(x, y, color)
  759.    int x, y;
  760.    COORD3 color;
  761. {
  762.    Rect r;
  763. #if defined(USE_CUSTOM_PALETTE)
  764.    int color_index;
  765. #else
  766.    RGBColor    rgbc;
  767. #endif
  768.  
  769.    r.top = y;
  770.    r.left = x;
  771.    r.bottom = y+1;
  772.    r.right = x+1;
  773. #if defined(USE_CUSTOM_PALETTE)
  774.    color_index = determine_color_index(color);
  775.    PmForeColor(color_index);
  776. #else
  777.    Coord3ToRGBColor(color, &rgbc);
  778.    RGBForeColor(&rgbc);
  779. #endif
  780.    PaintRect(&r);
  781.    return;
  782. }
  783.  
  784. /*------------------------------------------------------------*/
  785. void
  786. display_plot(x, y, color)
  787.    int x, y;
  788.    COORD3 color;
  789. {
  790.    double xt, yt;
  791.  
  792.    if (gMultiTaskCount++ > MAX_TASK_WAIT)
  793.    {
  794.           gMultiTaskCount = 0;
  795.        MacMultiTask();
  796.    }
  797.    yt = maxy/2 - Y_Display_Scale * y;
  798.    xt = maxx/2 + X_Display_Scale * x;
  799.  
  800.    if (xt < 0.0) x = 0;
  801.    else if (xt > 320.0) x = 320;
  802.    else x = (int)xt;
  803.    if (yt < 0.0) y = 0;
  804.    else if (yt > 240.0) y = 240;
  805.    else y = (int)yt;
  806.  
  807.    putpixel(x, y, color);
  808. }
  809.  
  810. /*------------------------------------------------------------*/
  811. void
  812. display_line(x0, y0, x1, y1, color)
  813.    int x0, y0, x1, y1;
  814.    COORD3 color;
  815. {
  816.    double xt, yt;
  817.    int color_index;
  818.  
  819.    if (gMultiTaskCount++ > MAX_TASK_WAIT)
  820.    {
  821.           gMultiTaskCount = 0;
  822.        MacMultiTask();
  823.    }
  824.  
  825.    /* Scale from image size to actual screen pixel size */
  826.    yt = maxy/2 - Y_Display_Scale * y0;
  827.    xt = maxx/2 + X_Display_Scale * x0;
  828.  
  829.    /* Clip the line to the viewport */
  830.    if (xt < 0.0)
  831.       x0 = 0;
  832.    else if (xt > maxx) {
  833.       x0 = maxx - 1;
  834.       }
  835.    else x0 = (int)xt;
  836.    if (yt < 0.0)
  837.       y0 = 0;
  838.    else if (yt > maxy) {
  839.       y0 = maxy;
  840.       }
  841.    else
  842.       y0 = (int)yt;
  843.  
  844.    yt = maxy/2 - Y_Display_Scale * y1;
  845.    xt = maxx/2 + X_Display_Scale * x1;
  846.    if (xt < 0.0)
  847.       x1 = 0;
  848.    else if (xt > maxx) {
  849.       x1 = maxx - 1;
  850.       }
  851.    else x1 = (int)xt;
  852.    if (yt < 0.0)
  853.       y1 = 0;
  854.    else if (yt > maxy) {
  855.       y1 = maxy;
  856.       }
  857.    else
  858.       y1 = (int)yt;
  859.  
  860. #if defined(USE_CUSTOM_PALETTE)
  861.    color_index = determine_color_index(color);
  862.    PmForeColor(color_index);
  863. #else
  864.    {
  865.    RGBColor    rgbc;
  866.  
  867.    Coord3ToRGBColor(color, &rgbc);
  868.    RGBForeColor(&rgbc);
  869.    }
  870. #endif
  871.    MoveTo(x0, y0);
  872.    LineTo(x1, y1);
  873. }
  874.  
  875.  
  876. /*------------------------------------------------------------*/
  877. /* general dialog constants */
  878. #define    Ditem_ET_SizePrompt        4
  879. #define    Ditem_BT_GetInFile        5
  880. #define    Ditem_ST_InFileName        6
  881. #define    Ditem_RB_RTO_BuiltIn    7
  882. #define    Ditem_RB_RTO_TriMesh    8
  883. #define    Ditem_ST_OutTitle        9
  884. #define    Ditem_PU_OutFormat        10
  885. #define    Ditem_ST_SizeText1        11
  886. #define    Ditem_ST_SizeText2        12
  887. #define    Ditem_ST_RTO_Title        13
  888. #define    Ditem_MAX                Ditem_ST_RTO_Title
  889.  
  890. // STR# resource IDs for this dialog
  891. #define    StrID_APP_NAME            2000
  892. #define    StrID_SIZE_PROMPT        2001
  893. #define    StrID_INFILE_PROMPT        2002
  894. #define    StrID_PATCH_PROMPT        2003
  895.  
  896. // popup menu ID
  897. #define    MenuID_OutFormat        1000
  898.  
  899. /*------------------------------------------------------------*/
  900. /* Put up dialog of options, and return TRUE if user clicks ok, else FALSE if cancel */
  901. static Boolean GetUserOptions(int spdType)
  902. {
  903.     short            itemHit;
  904.     short            k, dummy;
  905.     DialogPtr        myDialog;
  906.     Rect            displayRect;
  907.     ControlHandle    theDItems[Ditem_MAX+1];
  908.     char            aString[64];
  909.     Str15            thePatchPrompt;
  910.     Str31            appVers;
  911.     Str63            theInFilePrompt;
  912.     Str63            theAppName;
  913.     Str255            theSizePrompt;
  914.  
  915.     // load the dialog
  916.     myDialog = SetupNewDialog(DlogID_GETOPTS, true);
  917.     if (!myDialog)
  918.     {
  919.         SysBeep(4);
  920.         ExitToShell();
  921.     }
  922.  
  923.     // preload all the dialog items we care about
  924.     for (k = 1; k<=Ditem_MAX; k++)
  925.         GetDItem(myDialog, k, &dummy, (Handle *) &theDItems[k], &displayRect);
  926.  
  927.     // Get app-specific strings from resources
  928.     GetIndString(theAppName,        StrID_APP_NAME,        spdType);
  929.     GetIndString(theSizePrompt,        StrID_SIZE_PROMPT,    spdType);
  930.     GetIndString(theInFilePrompt,    StrID_INFILE_PROMPT,spdType);
  931.     GetIndString(thePatchPrompt,    StrID_PATCH_PROMPT, spdType);
  932.  
  933.     // SPD Version
  934. //    strcpy(aString, lib_get_version_str());
  935. //    c2pstr(aString);
  936.     // get Mac version from resource instead
  937.         GetAppVersionPString(1, appVers);
  938.  
  939.     // fill in app-specific strings in dialog
  940.     ParamText(theAppName, theSizePrompt, theInFilePrompt, appVers);
  941.  
  942.     // see which dialog items to remove.  Some of these items are specific
  943.     // to certain apps only.  If the Size prompt resource string is empty,
  944.     // don't display the size prompt stuff.
  945.     gHasSizePrompt        = (theSizePrompt[0] != '\0');
  946.  
  947.     // If infile prompt is empty, don't display it.
  948.     gHasInFilePrompt    = (theInFilePrompt[0] != '\0');
  949.  
  950.     // If infile prompt is empty, don't display it.
  951.     gHasPatchPrompt    = (thePatchPrompt[0] != '\0');
  952.  
  953.     // Hide any items that we don't want now
  954.     if (!gHasSizePrompt)
  955.     {
  956.         MoveDItem(myDialog, Ditem_ET_SizePrompt, -1000, -1000);
  957.         MoveDItem(myDialog, Ditem_ST_SizeText1, -1000, -1000);
  958.         MoveDItem(myDialog, Ditem_ST_SizeText2, -1000, -1000);
  959.     }
  960.     if (!gHasInFilePrompt)
  961.     {
  962.         MoveControl(theDItems[Ditem_BT_GetInFile], -1000, -1000);
  963.         MoveDItem(myDialog, Ditem_ST_InFileName, -1000, -1000);
  964.     }
  965.     if (!gHasPatchPrompt)
  966.     {
  967.         MoveDItem(myDialog, Ditem_ST_RTO_Title, -1000, -1000);
  968.         MoveControl(theDItems[Ditem_RB_RTO_BuiltIn], -1000, -1000);
  969.         MoveControl(theDItems[Ditem_RB_RTO_TriMesh], -1000, -1000);
  970.     }
  971.  
  972.     // fill initial size value into dialog
  973.     sprintf(aString, "%d", gMacParmSize);
  974.     c2pstr(aString);
  975.     SetIText((Handle) theDItems[Ditem_ET_SizePrompt], (StringPtr)aString);
  976.  
  977.     // init the popup
  978.     if (!IPopupMenu(myDialog, MenuID_OutFormat, Ditem_ST_OutTitle, Ditem_PU_OutFormat, gMacRayTracerKind+1))
  979.     {
  980.         SysBeep(4);
  981.         return false;
  982.     }
  983.     // select something..
  984.     SelIText(myDialog, Ditem_ET_SizePrompt, 0, -1);
  985.  
  986.     // finally show the user our dialog
  987.     MoveWindowToMaxDevice(myDialog);
  988.     ShowWindow(myDialog);
  989.  
  990.     // prompt until user clicks ok or cancel
  991.     do
  992.     {
  993.         // Set the radio buttons
  994.         SetCtlValue(theDItems[Ditem_RB_RTO_BuiltIn], gMacDoBuiltIn);
  995.         SetCtlValue(theDItems[Ditem_RB_RTO_TriMesh], !gMacDoBuiltIn);
  996.  
  997.         // get user input
  998.         ModalDialog(PopupMouseDnDialogFilterProc, &itemHit);
  999.  
  1000.         // process some user interface elements
  1001.         switch (itemHit)
  1002.         {
  1003.             case Ditem_RB_RTO_BuiltIn:
  1004.                 gMacDoBuiltIn = true;
  1005.                 break;
  1006.  
  1007.             case Ditem_RB_RTO_TriMesh:
  1008.                 gMacDoBuiltIn = false;
  1009.                 break;
  1010.  
  1011.             case Ditem_BT_GetInFile:
  1012.                 GetInputFile(gInFileName);
  1013.                 strcpy(aString, gInFileName);
  1014.                 c2pstr(aString);
  1015.                 SetIText((Handle) theDItems[Ditem_ST_InFileName], (StringPtr)aString);
  1016.                 break;
  1017.         }
  1018.     } while ((itemHit != ok) && (itemHit != cancel));
  1019.  
  1020.     if (itemHit == ok)
  1021.     {
  1022.  
  1023.         // Size
  1024.         if (gHasSizePrompt)
  1025.         {
  1026.             GetIText((Handle) theDItems[Ditem_ET_SizePrompt], (StringPtr)aString);
  1027.             p2cstr((StringPtr)aString);
  1028.             gMacParmSize = atoi(aString);
  1029.             if ((gMacParmSize < 1) || (gMacParmSize > 9))
  1030.                 gMacParmSize = 2;
  1031.         }
  1032.  
  1033.         // output format from popup
  1034.         gMacRayTracerKind = gPopupRec.fLastChoice - 1;
  1035.     }
  1036.  
  1037.     DisposeDialog(myDialog);
  1038.  
  1039.     // return TRUE if they hit OK
  1040.     return (itemHit == ok);
  1041.  
  1042. } /* GetUserOptions */
  1043.  
  1044.  
  1045. /*------------------------------------------------------------*/
  1046. static void AddArgvOpt(int *argcp, char ***argvp, char * optionStr)
  1047. {
  1048. #pragma unused (argvp)
  1049.     strcpy(argvCurrent, optionStr);
  1050.     macArgv[*argcp] = argvCurrent;
  1051.     argvCurrent += strlen(argvCurrent)+1; /* skip over string and null */
  1052.     (*argcp)++;
  1053. }
  1054.  
  1055.  
  1056. /*------------------------------------------------------------*/
  1057. void RedrawMyDialog(DialogPtr pDialogPtr)
  1058. {
  1059.     if (pDialogPtr)
  1060.     {
  1061.         SelectWindow(pDialogPtr);
  1062.         DrawDialog(pDialogPtr);
  1063.     }
  1064. } // RedrawDialog
  1065.  
  1066.  
  1067. /*------------------------------------------------------------*/
  1068. void MacInit(int *argcp, char ***argvp, int spdType)
  1069. {
  1070.     char    strTemp[10];
  1071.  
  1072.     // give us another 80k of stack space, 'cause we're so recursive
  1073.     SetApplLimit(GetApplLimit() - 80000);
  1074.     MaxApplZone();
  1075.  
  1076.     ToolBoxInit();
  1077.     if (!GetUserOptions(spdType))
  1078.         ExitToShell();
  1079.     else
  1080.     {
  1081.         SetCursor(*GetCursor(watchCursor));
  1082.         if (gMacRayTracerKind != OUTPUT_VIDEO)
  1083.         {
  1084.             /* put up "please wait" dialog */
  1085.             gDialogPtr = SetupNewDialog(DlogID_WAIT, false);
  1086.             if (gDialogPtr)
  1087.             {
  1088.                 ShowWindow(gDialogPtr);
  1089.                 RedrawMyDialog(gDialogPtr);
  1090.             }
  1091.             else
  1092.             {
  1093.                 SysBeep(4);
  1094.                 ExitToShell();
  1095.             }
  1096.         }
  1097.  
  1098.         *argcp = 0;            /* Set argc to 1 parm initially */
  1099.         *argvp = (char **)&macArgv;    /* point argv to our buffer */
  1100.         argvCurrent = (char *)&macArgvBuffer;    /* start at beginning of buffer */
  1101.  
  1102.         /*==== Program name is always first ====*/
  1103.         AddArgvOpt(argcp, argvp, "MacSPD");
  1104.  
  1105.         /*==== Raytracer Format ====*/
  1106.         AddArgvOpt(argcp, argvp, "-r");
  1107.         sprintf(strTemp, "%d", gMacRayTracerKind);
  1108.         AddArgvOpt(argcp, argvp, strTemp);
  1109.  
  1110.         /*==== Output Format (OUTPUT_CURVES,OUTPUT_PATCHES) ====*/
  1111.         if (gHasPatchPrompt)
  1112.         {
  1113.             if (gMacDoBuiltIn)
  1114.                 AddArgvOpt(argcp, argvp, "-c"); /*OUTPUT_CURVES*/
  1115.             else
  1116.                 AddArgvOpt(argcp, argvp, "-t"); /*OUTPUT_PATCHES*/
  1117.         }
  1118.  
  1119.         /*==== Size ====*/
  1120.         if (gHasSizePrompt)
  1121.         {
  1122.             AddArgvOpt(argcp, argvp, "-s");
  1123.             sprintf(strTemp, "%d", gMacParmSize);
  1124.             AddArgvOpt(argcp, argvp, strTemp);
  1125.         }
  1126.  
  1127.         /*==== Input File ====*/
  1128.         if (gHasInFilePrompt)
  1129.         {
  1130.             /* Input file name */
  1131.             AddArgvOpt(argcp, argvp, "-f");
  1132.             AddArgvOpt(argcp, argvp, gInFileName);
  1133.         }
  1134.     }
  1135. } /* MacInit */
  1136.  
  1137.  
  1138. /*------------------------------------------------------------*/
  1139. void MacMultiTask(void)
  1140. {
  1141.     EventRecord    anEvent;
  1142.     WaitNextEvent(everyEvent, &anEvent, 1, NULL);
  1143.  
  1144.     /* grody hack to redraw dialog on suspend/resume */
  1145.     if (anEvent.what == kOSEvent)
  1146.         if (((anEvent.message >> 24) & 0x0FF) == kSuspendResumeMessage)
  1147.         {    /* high byte of message */
  1148.             /* suspend/resume is also an activate/deactivate */
  1149.             RedrawMyDialog(gDialogPtr);
  1150.         }
  1151.  
  1152. } /* MacMultiTask */
  1153.  
  1154.  
  1155. /*------------------------------------------------------------*/
  1156. void MacShutDown(void)
  1157. {
  1158.     /* nothing needed for now */
  1159. } /* MacShutDown */
  1160.